#!/usr/bin/env bash

#  helper script: download u-boot
#
#	Copyright (C) 2014, 2015, 2016, 2020, 2021 Leah Rowe <info@minifree.org>
#	Copyright (C) 2021 Denis 'GNUtoo' Carikli  <GNUtoo@cyberdimension.org>
#
#	This program is free software: you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation, either version 3 of the License, or
#	(at your option) any later version.
#
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#
#	You should have received a copy of the GNU General Public License
#	along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

[ "x${DEBUG+set}" = 'xset' ] && set -v
set -u -e

# set this when you want to modify each u-boot tree
# for example, you want to test custom patches
# NODELETE= ./download coreboot
deleteblobs="true"
[ "x${NODELETE+set}" = 'xset' ] && deleteblobs="false"

# Error handling is extreme in this script.
# This script handles the internet, and Git. Both are inherently unreliable.
[[ -f build_error ]] && rm -f build_error

# Make sure that older revision are first as code uses that order to
# find the latest supported revision.
supported_uboot_revisions=" \
	v2021.07 \
"

downloadfor() {
	uboot_revision="v2021.07"
	uboot_dir="u-boot/u-boot"
	if [ -d "${uboot_dir}" ]; then
	    printf \
		"REMARK: '%s' directory already exists. Skipping setup.\n" \
		"${uboot_dir}"
		return 0
	fi

	if [ ! -d "${uboot_dir}" ]; then
		mkdir -p "${uboot_dir}"
	fi

	if [ ! -d "${uboot_dir}" ]; then
	    printf \
		"ERROR: '%s' directory not created. Check file system permissions\n" \
		"${uboot_dir}"
		return 1
	fi

	if [ ! -d "${uboot_dir}/.git" ] && [ -d "${uboot_dir}" ]; then
		rm -Rf "${uboot_dir}"
	fi

	if [ ! -d "${uboot_dir}" ]; then
		printf "Download u-boot from upstream:\n"
		git clone https://source.denx.de/u-boot/u-boot.git \
		    "${uboot_dir}" || \
		    rm -Rf "${uboot_dir}"
		if [ ! -d "${uboot_dir}" ]; then
		    printf \
			"ERROR: %s: Problem with git-clone. Network issue?\n" \
			"download/u-boot"
			return 1
		fi
	else
		git -C "${uboot_dir}" pull || touch build_error
		if [ -f build_error ]; then
		    printf \
			"ERROR: %s: Problem with git-pull. Network issue?\n" \
			"download/u-boot"
			return 1
		fi
	fi

	git -C "${uboot_dir}" reset --hard ${uboot_revision} || \
	    touch build_error
	if [ -f build_error ]; then
	    printf \
		"ERROR: %s: Unable to reset to commit ID/tag '%s' for board '%s' on tree '%s'\n" \
		"download/u-boot" "${uboot_revision}" "${1}" "${uboot_dir}"
		return 1
	fi
}

strip_comments()
{
	file="$1"
	# Remove comments
	sed 's/#.*//' "${file}" | \
	    # Remove lines composed of whitespaces only
	    sed '/^\W\+$/d' | \
		# Remove empty lines
		sed '/^$/d'
}

generate_deblob_script()
{
	blob_list_file="$1"
	output="$2"

	# Add sheebang and copyright headers from this file
	awk '{
		if ($0 !~ /^#/ && NF > 0) {
			stop=1;
		}
		if (stop !=1) {
			printf("%s\n", $0);
		}
	}' $0 >> ${output}

	# Add rm -rf before directories and rm -f before files
	awk \
	'{
	}{
		if (NF == 0) {
			printf("\n");
		} else {
			if ($0 !~ /#/ && $NF ~ /\/$/) {
				printf("rm -rf %s\n", $0);
			} else if ($0 !~ /#/) {
				printf("rm -f %s\n", $0);
			} else {
				# We have comments, try to see if they are
				# still valid paths before the comments
				comments_found=0
				last_field=0
				for(i=1; i<=NF; i++) {
					if($i ~ /#/) {
						comments_found=1;
					} else if(comments_found != 1) {
						last_field=i;
					}
				}
				if (last_field == 0) {
					printf("%s\n", $0);
				} else if ($last_field ~ /\/$/) {
					printf("rm -rf %s\n", $0);
				} else {
					printf("rm -f %s\n", $0);
				}
			}
		}
	}' "${blob_list_file}" >> "${output}"
}

usage()
{
	progname="./download u-boot"

	printf "Usage:\n"
	printf "\t%s                                # %s\n" \
	       "${progname}" \
	       "Download latest u-boot git revision and deblob it"
	printf "\t%s [revision]                     # %s\n" \
	       "${progname}" \
	       "Download given u-boot git revision and deblob it"
	printf "\t%s --blobs-list                   # %s\n" \
	       "${progname}" \
	       "Print the path of the blobs.list file for the latest supported u-boot revision"
	printf "\t%s --blobs-list [revision]        # %s\n" \
	       "${progname}" \
	       "Print the path of the blobs.list file for the given u-boot revision"
	printf "\t%s --gen-deblob-script            # %s\n" \
	       "${progname}" \
	       "Print the path of the generated deblob script for the latest supported u-boot revision"
	printf "\t%s --gen-deblob-script [revision] # %s\n" \
	       "${progname}" \
	       "Print the path of the generated deblob script for the given u-boot revision"
	printf "\t%s --list-revisions               # %s\n" \
	       "${progname}" \
	       "List supported u-boot revisions"
	printf "\t%s --help                         # %s\n" \
	       "${progname}" \
	       "Prints this help"
}

download_uboot_revision()
{
	git_revision="$1"

	printf "Downloading u-boot "
	printf "and (if exist in build system) applying patches\n"
	downloadfor "${git_revision}"

	rm -f "build_error"
	printf "\n\n"

	if [ "${deleteblobs}" = "true" ]; then
		blobslist="resources/u-boot/default/blobs.list"
		for blob_path in $(strip_comments "${blobslist}"); do
		    if echo "${blob_path}" | \
			    grep '/$' 2>&1 >/dev/null ; then
				printf "Deleting blob directory: '%s/%s'\n" \
				       "${uboot_dir}" "${blob_path}"
				rm -rf "${uboot_dir}/${blob_path}"
			else
				printf "Deleting blob file: '%s/%s'\n" \
				       "${uboot_dir}" "${blob_path}"
				rm -f "${uboot_dir}/${blob_path}"
			fi
		done
	fi
}

print_blobs_list_path()
{
	printf "resources/u-boot/default/blobs.list\n"
}

print_deblob_script_path()
{
	version="$1"
	path="$(mktemp)"

	generate_deblob_script "$(print_blobs_list_path ${version})" "${path}"
	printf "%s\n" ${path}
}

if [ $# -eq 0 ] ; then
	latest_revision="$(echo ${supported_uboot_revisions} | tail -n1)"
	download_uboot_revision "${latest_revision}"
	exit 0
elif [ $# -eq 1 -a "$1" == "--help" ] ; then
	usage
	exit 0
elif [ $# -eq 1 -a "$1" == "--list-revisions" ] ; then
	for revision in ${supported_uboot_revisions} ; do
		printf "${revision}\n"
	done
	exit 0
elif [ $# -eq 1 -a "$1" == "--blobs-list" ] ; then
	latest_revision="$(echo ${supported_uboot_revisions} | tail -n1)"
	print_blobs_list_path "${latest_revision}"
	exit 0
elif [ $# -eq 2 -a "$1" == "--blobs-list" ] ; then
	found=0
	for revision in ${supported_uboot_revisions} ; do
		if [ "${revision}" = "$2" ] ; then
			print_blobs_list_path "$2"
			exit 0
		fi
	done

	printf "Error: Revision '${1}' is not supported\n"

	exit 1
elif [ $# -eq 1 -a "$1" == "--gen-deblob-script" ] ; then
	latest_revision="$(echo ${supported_uboot_revisions} | tail -n1)"
	print_deblob_script_path "${latest_revision}"
	exit 0
elif [ $# -eq 2 -a "$1" == "--gen-deblob-script" ] ; then
	found=0
	for revision in ${supported_uboot_revisions} ; do
		if [ "${revision}" = "$2" ] ; then
			print_deblob_script_path "$2"
			exit 0
		fi
	done

	printf "Error: Revision '${1}' is not supported\n"

	exit 1
elif [ $# -eq 1 ] ; then
	found=0
	for revision in ${supported_uboot_revisions} ; do
		if [ "${revision}" = "$1" ] ; then
			download_uboot_revision "$1"
			exit 0
		fi
	done

	printf "Error: Revision '${1}' is not supported\n"

	exit 1
fi

exit 0
